'use client';

import { useClerk } from '@clerk/nextjs';
import clsx from 'clsx';
import { observer } from 'mobx-react-lite';
import { useRouter } from 'next/navigation';
import { useEffect, useState } from 'react';
import { useInView } from 'react-intersection-observer';

import { useStores } from '@/app/(root)/AppProviders';
import Button, { ButtonVariant } from '@/components/button/Button';
import ImageWithFallback from '@/components/image/ImageWithFallback';
import SongCard from '@/components/song/SongCard';
import SpinnerSVG from '@/components/svg/SpinnerSVG';
import TitleText from '@/components/title/TitleText';
import { Tooltip } from '@/components/tooltip/Tooltip';
import { usePreviewContext } from '@/context/PreviewContext';
import usePageViewLog from '@/hooks/usePageViewLog';
import { PlaySourceContextProvider } from '@/hooks/usePlaySource';
import { ArrowLeftIcon } from '@/icons';
import { ContextType } from '@/logging/contextTypes';
import { Clip } from '@/state/clipStore';
import { PERSONA_PAGE_SIZE, SMALL_IMAGE } from '@/utils/constants';
import { getClerkSignInRedirectProps, sleep } from '@/utils/utils';

import PersonaHeader from './PersonaHeader';
import PersonaShape from './PersonaShape';

const PersonaPageClient = observer(
  ({ personaId, isLoggedOut }: { personaId: string; isLoggedOut: boolean }) => {
    const router = useRouter();
    const clerk = useClerk();
    const {
      playbar,
      clips,
      library,
      session,
      persona,
      queue: queueStore,
    } = useStores();

    const [personaData, setPersonaData] = useState<any>(null);
    const [personaClipsData, setPersonaClipsData] = useState<Clip[]>([]);
    const [isInitialLoading, setIsInitialLoading] = useState(true);
    const [isPaginationLoading, setIsPaginationLoading] = useState(false);
    const [currentPage, setCurrentPage] = useState(1);
    const [hasMore, setHasMore] = useState(true);
    const [privateClipsCount, setPrivateClipsCount] = useState(0);
    const { setPreviewClip, setAllowFlushToTop } = usePreviewContext();

    const { ref: spinnerRef } = useInView({
      threshold: 0,
      rootMargin: '100px',
      triggerOnce: false,
      skip: isPaginationLoading || !hasMore,
      onChange: async (inView: boolean) => {
        if (inView && hasMore && !isPaginationLoading) {
          setIsPaginationLoading(true);
          try {
            const nextPage = currentPage + 1;
            const data = await persona.getPersonaPaginated(personaId, nextPage);

            if (data?.persona?.persona_clips?.length) {
              const filteredClips = data.persona.persona_clips
                .map((pc: any) => pc.clip)
                .filter(
                  (clip: any) =>
                    clip.is_public ||
                    (clip.id === data.persona.root_clip_id &&
                      data.persona.is_owned)
                );

              // Count private clips
              const privateClips = data.persona.persona_clips
                .map((pc: any) => pc.clip)
                .filter(
                  (clip: any) =>
                    !clip.is_public &&
                    !(
                      clip.id === data.persona.root_clip_id &&
                      data.persona.is_owned
                    )
                );
              setPrivateClipsCount((prev) => {
                return prev + privateClips.length;
              });

              setPersonaClipsData((prev) => [...prev, ...filteredClips]);
              setHasMore(data.total_results > nextPage * PERSONA_PAGE_SIZE);
              setCurrentPage(nextPage);
            } else {
              setHasMore(false);
            }
          } catch (error) {
            console.error('Error loading more clips:', error);
            setHasMore(false);
          } finally {
            setIsPaginationLoading(false);
          }
        }
      },
    });

    useEffect(() => {
      const fetchPersonaWithRetry = async (retries = 3, delay = 1000) => {
        for (let i = 0; i < retries; i++) {
          try {
            const data = await persona.getPersonaPaginated(personaId, 1);

            if (data?.persona) {
              const processedData = {
                ...data.persona,
                upvote_count: data.persona.upvote_count ?? 0,
                is_loved: data.persona.is_loved ?? false,
                is_following: data.persona.is_following ?? false,
              };

              setPersonaData(processedData);

              const filteredClips = (data.persona.persona_clips || [])
                .map((pc: any) => pc.clip)
                .filter(
                  (clip: any) =>
                    clip.is_public ||
                    (clip.id === data.persona.root_clip_id &&
                      data.persona.is_owned)
                );

              // Count private clips
              const privateClips = (data.persona.persona_clips || [])
                .map((pc: any) => pc.clip)
                .filter(
                  (clip: any) =>
                    !clip.is_public &&
                    !(
                      clip.id === data.persona.root_clip_id &&
                      data.persona.is_owned
                    )
                );
              setPrivateClipsCount(privateClips.length);
              setPersonaClipsData(filteredClips || []);
              setHasMore(data.total_results > filteredClips.length);
              setCurrentPage(data.current_page || 1);
              // setTotalResults(data.total_results);
            }
            setIsInitialLoading(false);
            return;
          } catch (error) {
            console.error(
              `Error fetching persona data (attempt ${i + 1}):`,
              error
            );
            if (i < retries - 1) {
              await sleep(delay);
            }
          }
        }
        setIsInitialLoading(false);
      };

      setIsInitialLoading(true);
      setCurrentPage(1);
      setPersonaClipsData([]);
      fetchPersonaWithRetry().finally(() => {
        setIsInitialLoading(false);
      });
    }, [personaId, persona]);

    usePageViewLog({
      actionName: 'PageViewed',
      componentContext: 'persona',
      principalObjectType: 'persona',
      principalObjectValue: personaId,
      context: { createdBy: personaData?.user_handle || '' },
    });

    useEffect(() => {
      if (personaData?.is_owned) {
        setPersonaData({
          ...personaData,
          ...{
            display_name: session.user?.display_name,
            profile_description: session.user?.profile_description,
            handle: session.user?.handle,
            avatar_image_url: session.user?.avatar_image_url,
          },
        });
      }
    }, [
      session.user?.display_name,
      session.user?.profile_description,
      session.user?.handle,
      session.user?.avatar_image_url,
    ]);

    useEffect(() => {
      playbar.setNoClipPlayCallback(() => {
        if (personaClipsData[0]) {
          playbar.playClip(personaClipsData[0]);
        }
      });
      setAllowFlushToTop(currentPage === 1);
      return () => {
        setAllowFlushToTop(false);
      };
    }, [personaClipsData, currentPage]);

    useEffect(() => {
      // Only update clips store with new clips
      const newClips = personaClipsData.filter(
        (clip) => !clips.clipById[clip.id]
      );
      if (newClips.length > 0) {
        clips.updateClips(newClips);
      }

      // Only set the queue context on initial load
      if (currentPage === 1 && !playbar.clip) {
        library.clipIds = personaClipsData.map((clip: Clip) => clip.id);
        queueStore.setPlayContext({
          contextType: ContextType.Persona,
          contextId: personaId,
          clips: personaClipsData,
        });
      }
    }, [personaClipsData, currentPage]);

    useEffect(() => {
      if (playbar.clip && playbar.isPlaying) {
        setPreviewClip(playbar.clip || null);
      }
    }, [playbar.clip]);

    if (isLoggedOut) {
      return (
        <div className='flex min-h-screen w-full flex-col items-center justify-center'>
          <div className='relative mb-4 aspect-square w-80'>
            <div className='relative mx-auto w-full overflow-hidden bg-inherit pb-[100%]'>
              <PersonaShape className='absolute inset-0 h-full w-full text-white' />
              <div className='absolute inset-0 z-10 flex flex-col items-center justify-center'>
                <div className='mb-4 text-lg text-white'>
                  Sign in to view Personas
                </div>
                <Button
                  variant={ButtonVariant.Primary}
                  onClick={() =>
                    clerk.openSignIn({
                      withSignUp: true,
                      ...getClerkSignInRedirectProps(`/persona/${personaId}`),
                    })
                  }
                >
                  Sign In
                </Button>
              </div>
            </div>
          </div>
        </div>
      );
    }
    return (
      <div
        className={`h-full w-full overflow-x-hidden overflow-y-auto ${playbar.clip ? 'pb-[100px]' : ''}`}
        style={{ scrollbarWidth: 'none' }}
      >
        <div className='h-auto w-full overflow-x-hidden'>
          {isInitialLoading ? (
            <div className='flex h-screen w-full items-center justify-center'>
              <SpinnerSVG />
            </div>
          ) : !personaData ? (
            <div className='mt-16 ml-8'>
              <div className='mb-4 font-serif text-lg'>
                This Persona could not be found.
              </div>
              <Button
                variant={ButtonVariant.Primary}
                icon={ArrowLeftIcon}
                onClick={() => router.push('/')}
              >
                Back to Suno
              </Button>
            </div>
          ) : (
            <>
              <PersonaHeader
                persona={personaData}
                clips={personaClipsData.map(
                  (clip: any) => clips.clipById[clip.id]
                )}
              />
              <div className='top-0 z-50 flex hidden flex-col p-8 sm:relative md:sticky'>
                <div className='flex flex-col md:flex-row'>
                  <div className='flex flex-col justify-center'>
                    <div className='flex w-full flex-row flex-wrap items-center gap-4'>
                      <ImageWithFallback
                        imageSize={SMALL_IMAGE}
                        className={clsx(
                          'h-[80px] w-[80px] rounded-full object-cover',
                          {
                            'cursor-pointer':
                              session.user?.handle === personaData.handle,
                          }
                        )}
                        src={personaData.avatar_image_url}
                        alt='Persona avatar'
                      />
                      <div className='flex flex-col justify-center'>
                        <div className='mb-2 flex flex-row items-end'>
                          <button
                            className={`mr-4 line-clamp-1 max-w-[800px] ${
                              session.user?.handle === personaData.handle
                                ? 'cursor-pointer'
                                : ''
                            }`}
                            data-testid='persona-heading'
                          >
                            <TitleText text={personaData.name} />
                          </button>
                        </div>
                        <span
                          className={`text-quatenary line-clamp-2 max-w-[600px] text-sm font-medium ${
                            session.user?.handle === personaData.handle
                              ? 'cursor-pointer'
                              : ''
                          }`}
                          data-testid='persona-description'
                        >
                          {personaData.description}
                        </span>
                      </div>
                    </div>
                  </div>
                  <div className='flex flex-1 flex-row items-center md:flex-row-reverse'>
                    <div className='mx-2 mt-2 flex flex-row justify-start md:mt-0 md:justify-end'>
                      <div className='mr-6 flex w-fit items-center gap-2 text-[rgba(255,255,255,0.5)]'></div>
                    </div>
                  </div>
                </div>
              </div>

              <div
                className={`justify-left flex flex-row flex-wrap gap-4 px-4 py-6 lg:gap-8 lg:px-8`}
              >
                <PlaySourceContextProvider
                  playSourceType='persona_page'
                  playSourceId={personaId}
                >
                  {!personaClipsData || personaClipsData.length === 0 ? (
                    <div className='mt-4 flex w-full items-center justify-center'>
                      <div className='text-md font-serif text-primary'>
                        {`${personaData?.name || 'This Persona'} doesn't have any public songs yet.`}
                      </div>
                    </div>
                  ) : (
                    <>
                      {personaClipsData
                        .map((clip: any) => clips.clipById[clip.id])
                        .map((clip: Clip, index: number, clips: Clip[]) =>
                          !!clip ? (
                            <SongCard
                              clip={clip}
                              key={clip.id}
                              onClick={() => {
                                if (
                                  playbar.clip?.id === clip.id &&
                                  queueStore.contextType ===
                                    ContextType.Persona &&
                                  queueStore.contextId === personaId
                                ) {
                                  playbar.togglePlay();
                                  return;
                                }
                                queueStore.setPlayContext({
                                  contextType: ContextType.Persona,
                                  contextId: personaId,
                                  clips,
                                  currentIndex: index,
                                });
                                playbar.playClip(clip);
                              }}
                              onPlay={() => {
                                if (
                                  playbar.clip?.id === clip.id &&
                                  queueStore.contextType ===
                                    ContextType.Persona &&
                                  queueStore.contextId === personaId
                                ) {
                                  playbar.togglePlay();
                                  return;
                                }
                                queueStore.setPlayContext({
                                  contextType: ContextType.Persona,
                                  contextId: personaId,
                                  clips,
                                  currentIndex: index,
                                });
                                playbar.playClip(clip);
                              }}
                              contextType={ContextType.Persona}
                              contextId={personaId}
                              index={index}
                              isRootClip={clip.id === personaData.root_clip_id}
                            />
                          ) : null
                        )}
                      {/* Private clips placeholder */}
                      {privateClipsCount > 0 && personaData?.is_owned && (
                        <div className='flex h-[200px] w-24 flex-col items-center justify-center rounded-lg text-center select-none'>
                          <Tooltip
                            label='Only public songs will appear in your public persona'
                            placement='bottom'
                            color='white'
                            background='#333333'
                            textAlign='center'
                            maxWidth='200px'
                          >
                            <div>
                              <div className='font-large text-lg'>
                                +{privateClipsCount}
                              </div>
                              <div className='font-large text-sm'>
                                Non-Public
                              </div>
                            </div>
                          </Tooltip>
                        </div>
                      )}
                      {/* Load more trigger */}
                      {hasMore && (
                        <div
                          className='flex h-auto w-full items-center justify-center'
                          ref={spinnerRef}
                        >
                          {isPaginationLoading && <SpinnerSVG />}
                        </div>
                      )}
                    </>
                  )}
                </PlaySourceContextProvider>
              </div>
            </>
          )}
        </div>
      </div>
    );
  }
);

export default PersonaPageClient;
